package web

import (
	"errors"
	"forum/internal/application"
	"forum/internal/common"
	"forum/internal/domain"
	"github.com/dlclark/regexp2"
	"github.com/gin-gonic/gin"
	"net/http"
)

const (
	emailRegexPattern    = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"
	passwordRegexPattern = `^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$`
)

type UserHandler struct {
	userSvc    application.UserService
	jwtHandler application.JwtService

	//验证器
	emailRegexp    *regexp2.Regexp
	passwordRegexp *regexp2.Regexp
}

func NewUserHandler(userSvc application.UserService, jwtHandler application.JwtService) *UserHandler {
	return &UserHandler{
		userSvc:        userSvc,
		jwtHandler:     jwtHandler,
		emailRegexp:    regexp2.MustCompile(emailRegexPattern, regexp2.None),
		passwordRegexp: regexp2.MustCompile(passwordRegexPattern, regexp2.None)}
}

func (u *UserHandler) RegisterRouter(server *gin.Engine) {
	userServer := server.Group("/user")
	userServer.POST("/signup", u.Signup)
	userServer.POST("/login", u.Login)
	userServer.POST("/refreshToken", u.RefreshToken)
}

func (u *UserHandler) Signup(ctx *gin.Context) {
	type Req struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}
	var req Req
	err := ctx.Bind(&req)
	if err != nil {
		return
	}
	//正则验证
	isEmailMatch, err := u.emailRegexp.MatchString(req.Email)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    10001,
			Message: "系统错误",
			Data:    nil,
		})
		return
	}
	if !isEmailMatch {
		ctx.JSON(http.StatusOK, Response{
			Code:    10002,
			Message: "邮箱格式不正确",
			Data:    nil,
		})
		return
	}
	isPasswordMatch, err := u.passwordRegexp.MatchString(req.Password)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    10001,
			Message: "系统错误",
			Data:    nil,
		})
		return
	}
	if !isPasswordMatch {
		ctx.JSON(http.StatusOK, Response{
			Code:    10003,
			Message: "密码格式不正确",
			Data:    nil,
		})
		return
	}

	err = u.userSvc.SignupByEmail(ctx, domain.User{
		Email:    req.Email,
		Password: req.Password,
	})
	if errors.Is(err, common.ErrRepeatEmail) {
		ctx.JSON(http.StatusOK, Response{
			Code:    10006,
			Message: "邮箱已注册",
			Data:    nil,
		})
		return
	}
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    10004,
			Message: "系统繁忙",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    10000,
		Message: "注册成功",
		Data:    nil,
	})
}

func (u *UserHandler) Login(ctx *gin.Context) {
	type Req struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}
	var req Req
	err := ctx.Bind(&req)
	if err != nil {
		return
	}

	user, err := u.userSvc.LoginByEmail(ctx, domain.User{
		Email:    req.Email,
		Password: req.Password,
	})
	if errors.Is(err, common.ErrPassword) {
		ctx.JSON(http.StatusOK, Response{
			Code:    11001,
			Message: "密码错误",
			Data:    nil,
		})
		return
	}
	if err != nil {
		ctx.JSON(http.StatusOK, Response{Code: 11002, Message: "系统错误", Data: nil})
		return
	}
	//生成JWT
	err = u.jwtHandler.SetLoginJwtToken(ctx, user.Id)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    11005,
			Message: "系统错误！",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    11000,
		Message: "登录成功！",
		Data:    user.Id,
	})
}

func (u *UserHandler) RefreshToken(ctx *gin.Context) {
	err := u.jwtHandler.RefreshToken(ctx)
	if errors.Is(err, common.ErrRefreshToken) {
		ctx.JSON(http.StatusOK, Response{
			Code:    12001,
			Message: "刷新失败",
			Data:    nil,
		})
		return
	}
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    12002,
			Message: "刷新失败",
			Data:    nil,
		})
		return
	}
	value := ctx.MustGet("claim").(application.RefreshClaim)
	err = u.jwtHandler.SetShortToken(ctx, value.Id)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    12004,
			Message: "刷新失败",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    12000,
		Message: "刷新成功",
		Data:    nil,
	})
	return
}

func (u *UserHandler) Logout(ctx *gin.Context) {
	err := u.jwtHandler.ClearToken(ctx)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    13001,
			Message: "退出登录失败",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    13000,
		Message: "退出登录成功",
		Data:    nil,
	})
}
